﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;

namespace MDXTest
{

    class MicCapture
    {
        Capture capture;
        CaptureBuffer buffer;
        AutoResetEvent captureEvent;
        int readPos, capturePos, lastReadPos;

        public MicCapture(double bufsec, int rate, short channels, short rez)
        {
            CaptureBufferDescription desc = new CaptureBufferDescription();
            desc.ControlEffects = false;
            desc.WaveMapped = true;
            desc.Format = getWaveFormat(rate, channels, rez);
            desc.BufferBytes = (int)(desc.Format.AverageBytesPerSecond * bufsec);

            capture = new Capture();
            this.buffer = new CaptureBuffer(desc, capture); 
        }

        public Capture Capture
        {
            get
            {
                return this.capture;
            }
        }

        public CaptureBuffer CaptureBuffer
        {
            get
            {
                return this.buffer;
            }
        }

        public void StartCapture(int cps)
        {
            captureEvent = new AutoResetEvent(false);

            BufferPositionNotify[] list = new BufferPositionNotify[cps];
            for (int i = 0; i < cps; i++)
            {
                list[i] = new BufferPositionNotify();
                list[i].EventNotifyHandle = captureEvent.Handle;
                list[i].Offset = this.CaptureBuffer.Format.AverageBytesPerSecond * (i + 1) / cps - 1;
            }

            Notify notify = new Notify(this.CaptureBuffer);
            notify.SetNotificationPositions(list);

            CaptureBuffer.Start(true);
        }

        public void StopCapture()
        {
            CaptureBuffer.Stop();
        }

        public SoundData QueryFrame()
        {
            captureEvent.WaitOne();
            int readPos;
            CaptureBuffer.GetCurrentPosition(out capturePos, out readPos);
            int size = readPos - lastReadPos;
            if (size == 0) return null;
            if (size < 0) size += CaptureBuffer.Caps.BufferBytes;
            // shortで読む場合、読み込むサイズをsizeof(short)で割らないとエラーになる
            short[] CapturedData = (short[])CaptureBuffer.Read(lastReadPos, typeof(short), LockFlag.None,
                 size / 2);
            //ここでcaptureDataにあるデータを処理する
            lastReadPos = readPos;

            return SoundData.FromArray(CapturedData);
        }

        public void Dispose()
        {
            capture.Dispose();
            buffer.Dispose();
        }

        public static WaveFormat getWaveFormat(int rate = 44100, short channels = 1, short rez = 16)
        {

            WaveFormat format = new WaveFormat();
            format.FormatTag = WaveFormatTag.Pcm;
            format.SamplesPerSecond = rate;
            format.Channels = channels;
            format.BitsPerSample = rez;
            format.BlockAlign = (short)(format.Channels * format.BitsPerSample / 8);
            format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign;
            return format;
        }
    }

    class MicCaptureInfo
    {
        public WaveFormat Format;
        public double BufferSeconds;
        public int BufferBytes;
        public int CapturePerSec;
        private int rate;
        private short channels;
        private short rez;

        public void setWaveFormat(int rate, short channels, short rez)
        {
            this.rate = rate;
            this.channels = channels;
            this.rez = rez;

            Format = new WaveFormat();
            Format.FormatTag = WaveFormatTag.Pcm;
            Format.SamplesPerSecond = rate;
            Format.Channels = channels;
            Format.BitsPerSample = rez;
            Format.BlockAlign = (short)(Format.Channels * Format.BitsPerSample / 8);
            Format.AverageBytesPerSecond = Format.SamplesPerSecond * Format.BlockAlign;
        }
    }
}